#pragma once

/****************************************************************************
** $Id: dl_dxf.h 2398 2005-06-06 18:12:14Z andrew $
**
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
**
** This file is part of the dxflib project.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid dxflib Professional Edition licenses may use 
** this file in accordance with the dxflib Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.ribbonsoft.com for further details.
**
** Contact info@ribbonsoft.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

#ifndef DL_DXF_H
#define DL_DXF_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __GCC2x__
#include <sstream>
#endif

#include "DL_Attributes.h"
#include "DL_Codes.h"
#include "DL_Entities.h"
#include "DL_Writer_Ascii.h"

#ifdef _WIN32
#undef M_PI
#define M_PI   3.14159265358979323846
#pragma warning(disable : 4800)
#endif

#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif

class DL_CreationInterface;
class DL_WriterA;


#define DL_VERSION     "2.0.4.8"

#define DL_UNKNOWN               0
#define DL_LAYER                10
#define DL_BLOCK                11
#define DL_ENDBLK               12
#define DL_LINETYPE             13
#define DL_SETTING              50
#define DL_ENTITY_POINT        100
#define DL_ENTITY_LINE         101
#define DL_ENTITY_POLYLINE     102
#define DL_ENTITY_LWPOLYLINE   103
#define DL_ENTITY_VERTEX       104
#define DL_ENTITY_SPLINE       105
#define DL_ENTITY_KNOT         106
#define DL_ENTITY_CONTROLPOINT 107
#define DL_ENTITY_ARC          108
#define DL_ENTITY_CIRCLE       109
#define DL_ENTITY_ELLIPSE      110
#define DL_ENTITY_INSERT       111
#define DL_ENTITY_TEXT         112
#define DL_ENTITY_MTEXT        113
#define DL_ENTITY_DIMENSION    114
#define DL_ENTITY_LEADER       115
#define DL_ENTITY_HATCH        116
#define DL_ENTITY_ATTRIB       117
#define DL_ENTITY_IMAGE        118
#define DL_ENTITY_IMAGEDEF     119
#define DL_ENTITY_TRACE        120
#define DL_ENTITY_SOLID        121
#define DL_ENTITY_SEQEND       122


/**
* Reading and writing of DXF files.
*
* This class can read in a DXF file and calls methods from the 
* interface DL_EntityContainer to add the entities to the
* contianer provided by the user of the library.
*
* It can also be used to write DXF files to a certain extent.
*
* When saving entities, special values for colors and linetypes 
* can be used:
*
* Special colors are 0 (=BYBLOCK) and 256 (=BYLAYER).
* Special linetypes are "BYLAYER" and "BYBLOCK".
*
* @author Andrew Mustun
*/

class DL_Dxf
{
public:
	DL_Dxf(void);
	~DL_Dxf(void);

public:
	BOOL in(CString file, DL_CreationInterface* creationInterface);
	BOOL readDxfGroups(FILE* fp, DL_CreationInterface* creationInterface, int* errorCounter = NULL);
	static BOOL getChoppedLine(char* s, unsigned int size, FILE* stream);

#ifndef __GCC2x__

	BOOL in(std::stringstream &stream,DL_CreationInterface* creationInterface);
	BOOL readDxfGroups(std::stringstream &stream,DL_CreationInterface* creationInterface,int* errorCounter = NULL);
	static BOOL getChoppedLine(char *s, unsigned int size,std::stringstream &stream);
#endif

public:
	static BOOL stripWhiteSpace(char **s);
	BOOL processDXFGroup(DL_CreationInterface*  creationInterface, int groupCode, const char* groupValue);
	void addSetting(DL_CreationInterface* creationInterface);
	void addLayer(DL_CreationInterface* creationInterface);
	void addBlock(DL_CreationInterface* creationInterface);
	void endBlock(DL_CreationInterface* creationInterface);

	void addPoint(DL_CreationInterface* creationInterface);
	void addLine(DL_CreationInterface* creationInterface);

	void addPolyline(DL_CreationInterface* creationInterface);
	void addVertex(DL_CreationInterface* creationInterface);

	void addSpline(DL_CreationInterface* creationInterface);
	//void addKnot(DL_CreationInterface* creationInterface);
	//void addControlPoint(DL_CreationInterface* creationInterface);

	void addArc(DL_CreationInterface* creationInterface);
	void addCircle(DL_CreationInterface* creationInterface);
	void addEllipse(DL_CreationInterface* creationInterface);
	void addInsert(DL_CreationInterface* creationInterface);

	void addTrace(DL_CreationInterface* creationInterface);
	void addSolid(DL_CreationInterface* creationInterface);

	void addMText(DL_CreationInterface* creationInterface);
	BOOL handleMTextData(DL_CreationInterface* creationInterface);
	BOOL handleLWPolylineData(DL_CreationInterface* creationInterface);
	BOOL handleSplineData(DL_CreationInterface* creationInterface);
	BOOL handleLeaderData(DL_CreationInterface* creationInterface);
	BOOL handleHatchData(DL_CreationInterface* creationInterface);

	void addText(DL_CreationInterface* creationInterface);
	void addAttrib(DL_CreationInterface* creationInterface);
	DL_DimensionData getDimData();
	void addDimLinear(DL_CreationInterface* creationInterface);
	void addDimAligned(DL_CreationInterface* creationInterface);
	void addDimRadial(DL_CreationInterface* creationInterface);
	void addDimDiametric(DL_CreationInterface* creationInterface);
	void addDimAngular(DL_CreationInterface* creationInterface);
	void addDimAngular3P(DL_CreationInterface* creationInterface);
	void addLeader(DL_CreationInterface* creationInterface);
	void addHatch(DL_CreationInterface* creationInterface);
	void addImage(DL_CreationInterface* creationInterface);
	void addImageDef(DL_CreationInterface* creationInterface);

	void endEntity(DL_CreationInterface* creationInterface);

	void endSequence(DL_CreationInterface* creationInterface);

	int  stringToInt(const char* s, BOOL* ok=NULL);	

	DL_WriterA* out(const char* file,DL_Codes::version version=VER_2000);

	void writeHeader(DL_WriterA& dw);

	void writePoint(DL_WriterA& dw,const DL_PointData& data,const DL_Attributes& attrib);
	void writeLine(DL_WriterA& dw,const DL_LineData& data,const DL_Attributes& attrib);
	void writePolyline(DL_WriterA& dw,const DL_PolylineData& data,const DL_Attributes& attrib);
	void writeVertex(DL_WriterA& dw,const DL_VertexData& data);
	void writePolylineEnd(DL_WriterA& dw);
	void writeSpline(DL_WriterA& dw,const DL_SplineData& data,const DL_Attributes& attrib);
	void writeControlPoint(DL_WriterA& dw,const DL_ControlPointData& data);
	void writeKnot(DL_WriterA& dw,const DL_KnotData& data);
	void writeCircle(DL_WriterA& dw,const DL_CircleData& data,const DL_Attributes& attrib);
	void writeArc(DL_WriterA& dw,const DL_ArcData& data,const DL_Attributes& attrib);
	void writeEllipse(DL_WriterA& dw,const DL_EllipseData& data,const DL_Attributes& attrib);
	void writeInsert(DL_WriterA& dw,const DL_InsertData& data,const DL_Attributes& attrib);
	void writeMText(DL_WriterA& dw,const DL_MTextData& data,const DL_Attributes& attrib);
	void writeText(DL_WriterA& dw,const DL_TextData& data,const DL_Attributes& attrib);
	void writeDimAligned(DL_WriterA& dw,const DL_DimensionData& data,const DL_DimAlignedData& edata,const DL_Attributes& attrib);
	void writeDimLinear(DL_WriterA& dw,const DL_DimensionData& data,const DL_DimLinearData& edata,const DL_Attributes& attrib);
	void writeDimRadial(DL_WriterA& dw,const DL_DimensionData& data,const DL_DimRadialData& edata,const DL_Attributes& attrib);
	void writeDimDiametric(DL_WriterA& dw,const DL_DimensionData& data,const DL_DimDiametricData& edata,const DL_Attributes& attrib);
	void writeDimAngular(DL_WriterA& dw,const DL_DimensionData& data,const DL_DimAngularData& edata,const DL_Attributes& attrib);
	void writeDimAngular3P(DL_WriterA& dw,const DL_DimensionData& data,const DL_DimAngular3PData& edata,const DL_Attributes& attrib);
	void writeLeader(DL_WriterA& dw,const DL_LeaderData& data,const DL_Attributes& attrib);
	void writeLeaderVertex(DL_WriterA& dw,const DL_LeaderVertexData& data);
	void writeHatch1(DL_WriterA& dw,const DL_HatchData& data,const DL_Attributes& attrib);
	void writeHatch2(DL_WriterA& dw,const DL_HatchData& data,const DL_Attributes& attrib);
	void writeHatchLoop1(DL_WriterA& dw,const DL_HatchLoopData& data);
	void writeHatchLoop2(DL_WriterA& dw,const DL_HatchLoopData& data);
	void writeHatchEdge(DL_WriterA& dw,const DL_HatchEdgeData& data);

	int writeImage(DL_WriterA& dw,const DL_ImageData& data,const DL_Attributes& attrib);

	void writeImageDef(DL_WriterA& dw, int handle,const DL_ImageData& data);

	void writeLayer(DL_WriterA& dw,const DL_LayerData& data,const DL_Attributes& attrib);

	void writeLineType(DL_WriterA& dw,const DL_LineTypeData& data);

	void writeAppid(DL_WriterA& dw, const string& name);

	void writeBlock(DL_WriterA& dw,const DL_BlockData& data);
	void writeEndBlock(DL_WriterA& dw, const string& name);

	void writeVPort(DL_WriterA& dw);
	void writeStyle(DL_WriterA& dw);
	void writeView(DL_WriterA& dw);
	void writeUcs(DL_WriterA& dw);
	void writeDimStyle(DL_WriterA& dw, double dimasz, double dimexe, double dimexo,double dimgap, double dimtxt);
	void writeBlockRecord(DL_WriterA& dw);
	void writeBlockRecord(DL_WriterA& dw, const string& name);
	void writeObjects(DL_WriterA& dw);
	void writeObjectsEnd(DL_WriterA& dw);

	/**
	* Converts the given string into a double or returns the given 
	* default valud (def) if value is NULL or empty.
	*/
	static double toReal(const char* value, double def = 0.0)
	{
		if(value != NULL && value[0] != '\0')
		{
			double ret;

			if(strchr(value, ',') != NULL)
			{
				char* tmp = new char[strlen(value) + 1];
				strcpy(tmp, value);
				DL_WriterA::strReplace(tmp, ',', '.');
				ret = atof(tmp);
				delete[] tmp;
			}
			else
			{
				ret = atof(value);
			}

			return ret;
		}
		else
		{
			return def;
		}
	}
	
	/**
	* Converts the given string into an int or returns the given 
	* default value (def) if value is NULL or empty.
	*/
	static int toInt(const char* value, int def = 0)
	{
		if(value != NULL && value[0] != '\0')
		{
			return atoi(value);
		}
		else
		{
			return def;
		}
	}

	/**
	* Converts the given string into a string or returns the given
	* default valud (def) if value is NULL or empty.
	*/
	static const char* toString(const char* value, const char* def = "")
	{
		if(value != NULL && value[0] != '\0')
		{
			return value;
		}
		else
		{
			return def;
		}
	}

	static BOOL checkVariable(const char* var, DL_Codes::version version);

	DL_Codes::version getVersion()
	{
		return version;
	}

	int getLibVersion(const char* str);

	//static void test();

private:
	 DL_Codes::version version;
	 unsigned long styleHandleStd;

	 string polylineLayer;
	 double* vertices;
	 int maxVertices;
	 int vertexIndex;

	 double* knots;
	 int maxKnots;
	 int knotIndex;

	 double* controlPoints;
	 int maxControlPoints;
	 int controlPointIndex;

	 double* leaderVertices;
	 int maxLeaderVertices;
	 int leaderVertexIndex;

	 // array of hatch loops
	 DL_HatchLoopData* hatchLoops;
	 int maxHatchLoops;
	 int hatchLoopIndex;
	 // array in format [loop#][edge#]
	 DL_HatchEdgeData** hatchEdges;
	 int* maxHatchEdges;
	 int* hatchEdgeIndex;
	 BOOL dropEdges;

	 // Bulge for the next vertex.
	 double bulge;

	 // Only the useful part of the group code
	 char groupCodeTmp[DL_DXF_MAXLINE+1];
	 // ...same as integer
	 unsigned int groupCode;
	 // Only the useful part of the group value
	 char groupValue[DL_DXF_MAXLINE+1];
	 // Current entity type
	 int currentEntity;
	 // Value of the current setting
	 char settingValue[DL_DXF_MAXLINE+1];
	 // Key of the current setting (e.g. "$ACADVER")
	 char settingKey[DL_DXF_MAXLINE+1];
	 // Stores the group codes
	 char values[DL_DXF_MAXGROUPCODE][DL_DXF_MAXLINE+1];
	 // First call of this method. We initialize all group values in
	 //  the first call.
	 BOOL firstCall;
	 // Attributes of the current entity (layer, color, width, line type)
	 DL_Attributes attrib;
	 // library version. hex: 0x20003001 = 2.0.3.1
	 int libVersion;

	 //CF-Start
	 bool bStartBlocks;
	 bool bEndBlocks;
	 //CF-End
};

#endif

//EOF